package qc.module.qms.service.calc;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import qc.common.core.constants.QmsConstant;
import qc.common.core.enums.qms.QmsPointTimeSegmentEnum;
import qc.common.core.enums.qms.QmsQueryPointDataTimeSegmentTypeEnum;
import qc.common.core.utils.LocalDateTimeUtil;
import qc.common.core.utils.QmsTimeUtil;
import qc.module.qms.algorithm.NumericCalc.dto.QmsNumericCalcPointRelation;
import qc.module.qms.algorithm.NumericCalc.dto.QmsNumericCalcUseMethod;
import qc.module.qms.algorithm.NumericCalc.dto.QmsNumericCalcUseMethodInputTsDatas;
import qc.module.qms.dto.calc.QmsPointDataCalcJudgeResultDto;
import qc.module.qms.entity.*;
import qc.module.qms.mapper.QmsCalcMethodInputMapper;
import qc.module.qms.mapper.QmsCalcMethodParamMapper;
import qc.module.qms.service.pointdata.QmsPointDataLatestService;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * QMS数值计算相关获取方法Service，提供获取点号的计算方法、计算输入（参数、点号数据）、触发关联点号等方法
 *
 * @author QuCheng Tech
 * @since 2025/9/11
 */
@Service
public class QmsNumericCalcGetService {
    private static final Logger logger = LoggerFactory.getLogger(QmsNumericCalcGetService.class);

    @Autowired
    private QmsCalcMethodRelatedElementService calcMethodElementService;

    @Autowired
    private QmsCalcMethodInputPointDataService calcMethodInputService;

    @Autowired
    private QmsCalcMethodInputParamService calcMethodParamService;

    @Autowired
    private QmsCalcMethodRelatedPointService calcMethodPointService;

    @Autowired
    private QmsCalcMethodService calcMethodService;

    @Autowired
    private QmsNumericCalcPointRelationService numericCalcPointRelationService;

    @Autowired
    private QmsPointDataLatestService pointDataLatestService;

    /**
     * 根据点号、时段类型获取最终采用的计算方法；按照点号关联的计算方法、监测要素关联的计算方法的顺序获取一个有效的计算方法
     *
     * @param point 点号对象
     * @param tmseg 时段类型
     * @return qc.module.qms.dto.numericcalc.QmsCalcUseMethod
     * @author QuCheng Tech
     * @since 2025/9/9
     */
    public QmsNumericCalcUseMethod getPointValidCalcUseMethod(QmsPoint point, QmsPointTimeSegmentEnum tmseg) {
        logger.debug("getPointCalcMethod 根据点号获取计算方法");
        if (point == null) {
            logger.error("getPointCalcMethod 根据点号获取计算方法，点号信息为null");
        } else {
            QmsNumericCalcUseMethod result = null;

            String pointid = point.getPointid();
            //先根据计算方法与点号关联直接获取，如果不存在或者为禁用状态再根据点号中的采集要素进行获取
            List<QmsCalcMethodPoint> pointMethods = this.getCalcMethodPoints(pointid, tmseg);
            if (pointMethods == null || pointMethods.size() < 0x1) {
                //点号没有直接关联的计算方法
                logger.info("getPointCalcMethod 根据点号获取计算方法，点号[" + pointid + "]，时段类型[" + tmseg.toString() + "]，无任何点号直接关联的计算方法");
            } else {
                //逐个判断是否有可用的计算方法，判断关联是启用状态，并且对应的计算方法也是启用状态
                logger.info("getPointCalcMethod 根据点号获取计算方法，点号[" + pointid + "]，时段类型[" + tmseg.toString() + "]，点号直接关联的计算方法共有[" + pointMethods.size() + "]个");
                for (QmsCalcMethodPoint method : pointMethods) {
                    if (method.getIsdisable() == false) {
                        //计算方法与点号关联关系未禁用，获取计算方法判断是否禁用
                        QmsCalcMethod methodEntity = this.getCalcMethod(method.getMethodcode());
                        if (methodEntity != null && methodEntity.getIsdisable() == false) {
                            //有效，使用当前计算方法作为返回的计算方法
                            logger.info("getPointCalcMethod 根据点号获取计算方法，点号[" + pointid + "]，时段类型[" + tmseg.toString() + "]，根据点号直接关联得到的有效计算方法[" + methodEntity.getMethodcode() + "]");
                            result = new QmsNumericCalcUseMethod();

                            result.setMethodcode(methodEntity.getMethodcode());
                            result.setMethodname(methodEntity.getMethodname());
                            result.setIntscount(methodEntity.getIntscount());
                            result.setContent(methodEntity.getContent());
                            //计算结果单位换算系数和时间长度类型使用点号关联中的设置
                            result.setValuemodulus(method.getValuemodulus());
                            result.setValuetmtype(method.getValuetmtype());

                            break;
                        }
                    }
                }
            }

            //判断如果根据点号直接关联的有效计算方法为null，根据点号的采集要素进行获取
            if (result == null) {
                logger.debug("getPointCalcMethod 根据点号监测要素获取计算方法，点号[" + pointid + "]，时段类型[" + tmseg.toString() + "]，根据点号直接关联未获取到有效的计算方法，开始根据点号监测要素获取计算方法");

                logger.debug("getPointCalcMethod 根据点号监测要素获取计算方法，点号[" + pointid + "]，时段类型[" + tmseg.toString() + "]，监测要素编码[" + point.getElecode() + "]");
                List<QmsCalcMethodElement> elementMethods = this.getCalcMethodElement(point.getElecode(), tmseg);
                if (elementMethods == null || elementMethods.size() < 0x1) {
                    //采集要素没有直接关联的计算方法
                    logger.info("getPointCalcMethod 根据点号监测要素获取计算方法，点号[" + pointid + "]，时段类型[" + tmseg.toString() + "]，监测要素编码[" + point.getElecode() + "]，无任何点号所属监测要素关联的计算方法");
                } else {
                    //逐个判断是否有可用的计算方法，判断关联是启用状态，并且对应的计算方法也是启用状态
                    logger.info("getPointCalcMethod 根据点号监测要素获取计算方法，点号[" + pointid + "]，时段类型[" + tmseg.toString() + "]，监测要素编码[" + point.getElecode() + "]，点号所属监测要素关联的计算方法共有[" + elementMethods.size() + "]个");
                    for (QmsCalcMethodElement method : elementMethods) {
                        if (method.getIsdisable() == false) {
                            //计算方法与监测要素关联关系未禁用，获取计算方法判断是否禁用
                            QmsCalcMethod methodEntity = this.getCalcMethod(method.getMethodcode());
                            if (methodEntity != null && methodEntity.getIsdisable() == false) {
                                //有效，使用当前计算方法作为返回的计算方法
                                logger.info("getPointCalcMethod 根据点号监测要素获取计算方法，点号[" + pointid + "]，时段类型[" + tmseg.toString() + "]，监测要素编码[" + point.getElecode() + "]，根据点号所属监测要素关联得到的有效计算方法[" + methodEntity.getMethodcode() + "]");
                                result = new QmsNumericCalcUseMethod();

                                result.setMethodcode(methodEntity.getMethodcode());
                                result.setMethodname(methodEntity.getMethodname());
                                result.setIntscount(methodEntity.getIntscount());
                                result.setContent(methodEntity.getContent());
                                //计算结果单位换算系数和时间长度类型使用点号关联中的设置
                                result.setValuemodulus(method.getValuemodulus());
                                result.setValuetmtype(method.getValuetmtype());

                                break;
                            }
                        }
                    }
                }
            }

            //最终获取到的计算方法不为空时获取方法配置的输入参数和时序数据
            if (result != null) {
                //获取计算方法的输入参数配置
                List<QmsCalcMethodParam> paramEns = this.getCalcMethodParams(result.getMethodcode());
                if (paramEns != null && paramEns.size() > 0x0)
                    result.setParams(QmsCalcMethodParamMapper.MAPPER.toUseList(paramEns));

                //获取计算方法的输入时序数据配置
                List<QmsCalcMethodInput> inputEns = this.getCalcMethodInputs(result.getMethodcode());
                if (inputEns != null && inputEns.size() > 0x0)
                    result.setIntsdatas(QmsCalcMethodInputMapper.MAPPER.toUseList(inputEns));
            }

            return result;
        }

        return null;
    }

    /**
     * 获取指定点号和时段类型的所有关联的计算方法，不管状态是否禁用
     *
     * @param pointid 点号
     * @param tmseg   时段类型
     * @return java.util.List<qc.module.qms.entity.QmsCalcMethodPoint>
     * @author QuCheng Tech
     * @since 2025/9/9
     */
    public List<QmsCalcMethodPoint> getCalcMethodPoints(String pointid, QmsPointTimeSegmentEnum tmseg) {
        if (StringUtils.isNotBlank(pointid) && tmseg != QmsPointTimeSegmentEnum.UN_DEFINE) {
            //点号ID为空或者时段类型错误时无法获取对应计算方法
            List<QmsCalcMethodPoint> allMethods = calcMethodPointService.getAllWithCache();
            if (allMethods != null && allMethods.size() > 0x0) {
                List<QmsCalcMethodPoint> filterMethods = allMethods.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getPointid(), pointid)
                        && p.getTmsegs() != null && p.getTmsegs().intValue() > 0x0 && (p.getTmsegs().intValue() & tmseg.getIndex()) == tmseg.getIndex()).collect(Collectors.toList());
                if (filterMethods != null && filterMethods.size() > 0x0)
                    return filterMethods;
            }
        }

        return null;
    }

    /**
     * 获取指定要素编码和时段类型的所有关联计算方法，不管状态是否禁用
     *
     * @param elementCode 采集要素编码
     * @param tmseg       时段类型
     * @return java.util.List<qc.module.qms.entity.QmsCalcMethodElement>
     * @author QuCheng Tech
     * @since 2025/9/9
     */
    public List<QmsCalcMethodElement> getCalcMethodElement(String elementCode, QmsPointTimeSegmentEnum tmseg) {
        if (StringUtils.isNotBlank(elementCode) && tmseg != QmsPointTimeSegmentEnum.UN_DEFINE) {
            //站点分类编码为空、要素编码为空或者时段类型错误时无法获取对应计算方法
            List<QmsCalcMethodElement> allMethods = calcMethodElementService.getAllWithCache();
            if (allMethods != null && allMethods.size() > 0x0) {
                List<QmsCalcMethodElement> filterMethods = allMethods.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getElecode(), elementCode)
                        && p.getTmsegs() != null && p.getTmsegs().intValue() > 0x0 && (p.getTmsegs().intValue() & tmseg.getIndex()) == tmseg.getIndex()).collect(Collectors.toList());
                if (filterMethods != null && filterMethods.size() > 0x0)
                    return filterMethods;
            }
        }

        return null;
    }

    /**
     * 获取指定编码的计算方法，有缓存时从缓存中获取
     *
     * @param methodCode 计算方法编码
     * @return qc.module.qms.entity.QmsCalcMethod
     * @author QuCheng Tech
     * @since 2025/9/11
     */
    public QmsCalcMethod getCalcMethod(String methodCode) {
        if (StringUtils.isNotBlank(methodCode)) {
            List<QmsCalcMethod> allMethods = calcMethodService.getAllWithCache();
            if (allMethods != null && allMethods.size() > 0x0) {
                Optional<QmsCalcMethod> method = allMethods.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getMethodcode(), methodCode)).findFirst();
                if (method != null && method.isPresent())
                    return method.get();
            }
        }

        return null;
    }

    /**
     * 获取指定计算方法的输入时序配置，优先从缓存中获取
     *
     * @param methodCode 计算法方法编码
     * @return java.util.List<qc.module.qms.entity.QmsCalcMethodInput>
     * @author QuCheng Tech
     * @since 2025/9/9
     */
    public List<QmsCalcMethodInput> getCalcMethodInputs(String methodCode) {
        if (StringUtils.isNotBlank(methodCode)) {
            //计算方法编码为空时无法获取关联的输入时序数据配置
            List<QmsCalcMethodInput> allInputs = calcMethodInputService.getAllWithCache();
            if (allInputs != null && allInputs.size() > 0x0) {
                List<QmsCalcMethodInput> filterMethodInputs = allInputs.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getMethodcode(), methodCode)).collect(Collectors.toList());
                if (filterMethodInputs != null && filterMethodInputs.size() > 0x0)
                    return filterMethodInputs;
            }
        }

        return null;
    }

    /**
     * 获取指定计算方法的输入参数配置
     *
     * @param methodCode 计算法方法编码
     * @return java.util.List<qc.module.qms.entity.QmsCalcMethodParam>
     * @author QuCheng Tech
     * @since 2025/9/9
     */
    public List<QmsCalcMethodParam> getCalcMethodParams(String methodCode) {
        if (StringUtils.isNotBlank(methodCode)) {
            //计算方法编码为空时无法获取关联的输入参数配置
            List<QmsCalcMethodParam> allParams = calcMethodParamService.getAllWithCache();
            if (allParams != null && allParams.size() > 0x0) {
                List<QmsCalcMethodParam> filterMethodParams = allParams.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getMethodcode(), methodCode)).collect(Collectors.toList());
                if (filterMethodParams != null && filterMethodParams.size() > 0x0)
                    return filterMethodParams;
            }
        }

        return null;
    }

    /**
     * 获取指定的点号作为计算输入数据的触发关联点号计算的关联关系
     *
     * @param pointid 点号ID
     * @param tmseg   点号时段类型
     * @return java.util.List<qc.module.qms.algorithm.NumericCalc.dto.QmsNumericCalcPointRelation>
     * @author QuCheng Tech
     * @since 2025/9/30
     */
    public List<QmsNumericCalcPointRelation> getPointTriggerRelations(String pointid, QmsPointTimeSegmentEnum tmseg) {
        logger.debug("getPoint 根据点号获取触发点号数值计算关联关系，点号[" + pointid + "]，时段类型[" + tmseg + "]");
        if (StringUtils.isNotBlank(pointid) && tmseg != null && tmseg != QmsPointTimeSegmentEnum.UN_DEFINE) {
            List<QmsNumericCalcPointRelation> allRelations = numericCalcPointRelationService.getAllWithCache();
            if (allRelations != null && allRelations.size() > 0x0) {
                //根据输入点号作为输入数据点号筛选关联关系
                List<QmsNumericCalcPointRelation> filterRelations = allRelations.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getInputPointid(), pointid) && p.getInputTmseg() == tmseg).collect(Collectors.toList());
                if (filterRelations != null && filterRelations.size() > 0x0) {
                    logger.debug("getPoint 根据点号获取触发点号数值计算关联关系，点号[" + pointid + "]，时段类型[" + tmseg + "]，该点号触发关联点号共[" + filterRelations.size() + "]个");
                    return filterRelations;
                } else {
                    logger.debug("getPoint 根据点号获取触发点号数值计算关联关系，点号[" + pointid + "]，时段类型[" + tmseg + "]，该点号不触发任何其他关联点号计算");
                }
            } else {
                logger.debug("getPoint 根据点号获取触发点号数值计算关联关系，点号[" + pointid + "]，时段类型[" + tmseg + "]，缓存的点号与触发关联点号关系集合为空");
            }
        }

        return null;
    }

    /**
     * 获取定时进行点号数据计算时本次要进行计算的点号时间段
     *
     * @param point       点号对象
     * @param tmseg       点号时段类型
     * @param calcMethod  计算方法
     * @param currentTime 当前时间
     * @return qc.module.qms.dto.calc.QmsPointDataCalcJobJudgeResultDto
     * @author QuCheng Tech
     * @since 2025/10/9
     */
    public QmsPointDataCalcJudgeResultDto getTimerJobCalcPointDataJudgeResult(QmsPoint point, QmsPointTimeSegmentEnum tmseg,
                                                                              QmsNumericCalcUseMethod calcMethod, LocalDateTime currentTime) {
        //初始化结果中是否需要计算为false
        QmsPointDataCalcJudgeResultDto result = new QmsPointDataCalcJudgeResultDto();
        result.setNeedCalc(false);

        //判断基本输入是否正确，不正确时设置对应的提示信息并返回结果
        if (point == null) {
            result.setMsg("计算的点号对象不能为空");
            return result;
        }
        if (StringUtils.isBlank(point.getPointid())) {
            result.setMsg("计算的点号编码不能为空");
            return result;
        }
        if (tmseg == null) {
            result.setMsg("计算的时段类型不能为空");
            return result;
        }
        if (tmseg == QmsPointTimeSegmentEnum.UN_DEFINE || tmseg == QmsPointTimeSegmentEnum.REAL || tmseg == QmsPointTimeSegmentEnum.MINUTE) {
            result.setMsg("计算的时段类型错误");
            return result;
        }
        //判断计算方法
        if (calcMethod == null) {
            result.setMsg("计算方法不能为空");
            return result;
        }
        //传入的时间为空时自动设置为当前时间
        if (currentTime == null)
            currentTime = LocalDateTimeUtil.getNow();

        //根据当前时间和时段类型计算当前时间所在的时段时间
        LocalDateTime currentPeriodTime = QmsTimeUtil.getPeriodTime(currentTime, tmseg);
        String pointid = point.getPointid();
        //获取计算方法中的输入点号数据序列的起始和截止时间偏移时段数
        Integer maxBeginTimeOffset = null;
        QmsPointTimeSegmentEnum maxBeginTimeOffsetTmseg = tmseg;
        Integer maxEndTimeOffset = null;
        QmsPointTimeSegmentEnum maxEndTimeOffsetTmseg = tmseg;
        if (calcMethod.getIntsdatas() != null && calcMethod.getIntsdatas().size() > 0x0) {
            for (QmsNumericCalcUseMethodInputTsDatas methodInputDatas : calcMethod.getIntsdatas()) {
                if (methodInputDatas.getTmbeginoffset() != null) {
                    //如果记录的最大开始时间偏移时段数为null或者数值小于当前配置中的数值
                    if (maxBeginTimeOffset == null || maxBeginTimeOffset.intValue() < methodInputDatas.getTmbeginoffset().intValue()) {
                        maxBeginTimeOffset = methodInputDatas.getTmbeginoffset();
                        //同步获取配置中的时段类型
                        if (methodInputDatas.getTmsegtype() == QmsQueryPointDataTimeSegmentTypeEnum.DESIGNATED
                                && methodInputDatas.getTmseg() != QmsPointTimeSegmentEnum.UN_DEFINE) {
                            //指定的时段类型有效
                            maxBeginTimeOffsetTmseg = methodInputDatas.getTmseg();
                        } else if (methodInputDatas.getTmsegtype() == QmsQueryPointDataTimeSegmentTypeEnum.SMALLER_ONE_THAN_DEST) {
                            //如果输入点号数据项中配置为比目标点号小一个时段类型，获取输入点号的有效时段类型进行计算；
                            //不需要获取输入点号中的时段类型，直接使用目前时段类型在目标点号中获取小一个时段的时段类型
                            maxBeginTimeOffsetTmseg = QmsPointTimeSegmentEnum.getSmallerOneTimeSegmentEnum(point.getTmsegs(), tmseg);
                        }
                    }
                }
                if (methodInputDatas.getTmendoffset() != null) {
                    //如果记录的最大开始时间偏移时段数为null或者数值小于当前配置中的数值
                    if (maxEndTimeOffset == null || maxEndTimeOffset.intValue() < methodInputDatas.getTmendoffset().intValue()) {
                        maxEndTimeOffset = methodInputDatas.getTmendoffset();//同步获取配置中的时段类型
                        if (methodInputDatas.getTmsegtype() == QmsQueryPointDataTimeSegmentTypeEnum.DESIGNATED
                                && methodInputDatas.getTmseg() != QmsPointTimeSegmentEnum.UN_DEFINE) {
                            //指定的时段类型有效
                            maxEndTimeOffsetTmseg = methodInputDatas.getTmseg();
                        } else if (methodInputDatas.getTmsegtype() == QmsQueryPointDataTimeSegmentTypeEnum.SMALLER_ONE_THAN_DEST) {
                            //如果输入点号数据项中配置为比目标点号小一个时段类型，获取输入点号的有效时段类型进行计算；
                            //不需要获取输入点号中的时段类型，直接使用目前时段类型在目标点号中获取小一个时段的时段类型
                            maxEndTimeOffsetTmseg = QmsPointTimeSegmentEnum.getSmallerOneTimeSegmentEnum(point.getTmsegs(), tmseg);
                        }
                    }
                }
            }
        }
        //点号要计算的时间段：需要查询点号最新状态中的数据时间
        //点号计算开始时段：如果有上次计算的时段时间则取下一个时段时间，如果没有默认计算前N个时段
        LocalDateTime pointLatestCalcPeriodTime = pointDataLatestService.getCalcDataTime(pointid, tmseg);
        LocalDateTime pointCalcBeginPeriodTime = null;
        if (pointLatestCalcPeriodTime != null) {
            //如果点号已有最新定时计算时段时间，本次计算的开始时间为下一个时段
            pointCalcBeginPeriodTime = QmsTimeUtil.getNextPeriodTime(pointLatestCalcPeriodTime, tmseg);
        } else {
            //点号没有最新定时计算时段时间，默认计算前N个时段时间
            if (tmseg == QmsPointTimeSegmentEnum.HOUR) {
                //小时数据计算前n天
                pointCalcBeginPeriodTime = QmsTimeUtil.getIntervalPeriodTime(currentPeriodTime, tmseg, -24 * QmsConstant.NO_MORE_THAN_DAY_PERIOD_MAX_BACKWARD_DAYS);
            } else if (tmseg == QmsPointTimeSegmentEnum.DAY) {
                //日数据计算前n天
                pointCalcBeginPeriodTime = QmsTimeUtil.getIntervalPeriodTime(currentPeriodTime, tmseg, -QmsConstant.NO_MORE_THAN_DAY_PERIOD_MAX_BACKWARD_DAYS);
            } else if (tmseg == QmsPointTimeSegmentEnum.WEEK) {
                //周数据计算前n周
                pointCalcBeginPeriodTime = QmsTimeUtil.getIntervalPeriodTime(currentPeriodTime, tmseg, -QmsConstant.MORE_THAN_DAY_PERIOD_MAX_BACKWARD_PERIODS);
            } else if (tmseg == QmsPointTimeSegmentEnum.TEN_DAYS) {
                //旬数据计算前n旬
                pointCalcBeginPeriodTime = QmsTimeUtil.getIntervalPeriodTime(currentPeriodTime, tmseg, -QmsConstant.MORE_THAN_DAY_PERIOD_MAX_BACKWARD_PERIODS);
            } else if (tmseg == QmsPointTimeSegmentEnum.MONTH) {
                //月数据计算前n月
                pointCalcBeginPeriodTime = QmsTimeUtil.getIntervalPeriodTime(currentPeriodTime, tmseg, -QmsConstant.MORE_THAN_DAY_PERIOD_MAX_BACKWARD_PERIODS);
            } else if (tmseg == QmsPointTimeSegmentEnum.QUARTER) {
                //季度数据计算前n季度
                pointCalcBeginPeriodTime = QmsTimeUtil.getIntervalPeriodTime(currentPeriodTime, tmseg, -QmsConstant.MORE_THAN_DAY_PERIOD_MAX_BACKWARD_PERIODS);
            } else if (tmseg == QmsPointTimeSegmentEnum.YEAR) {
                //年数据计算前n年
                pointCalcBeginPeriodTime = QmsTimeUtil.getIntervalPeriodTime(currentPeriodTime, tmseg, -QmsConstant.YEAR_PERIOD_MAX_BACKWARD_PERIODS);
            }
        }
        //点号计算截止时段：根据时段类型获取的当前时段
        LocalDateTime pointCalcEndPeriodTime = LocalDateTime.of(currentPeriodTime.toLocalDate(), currentPeriodTime.toLocalTime());
        //在根据计算方法中的输入数据设置判断计算时段是否完全结束
        if (maxBeginTimeOffset != null && maxBeginTimeOffset.intValue() != 0x0) {
            while (QmsTimeUtil.getIntervalPeriodTime(QmsTimeUtil.getNextPeriodTime(pointCalcBeginPeriodTime, tmseg), maxBeginTimeOffsetTmseg, maxBeginTimeOffset.intValue()).isAfter(currentTime)) {
                //如果计算开始时段的时段末时间（下一个时段时间点）加上取数据开始偏移时段数＞当前时间，需要设置计算开始时段往前一个时段
                pointCalcBeginPeriodTime = QmsTimeUtil.getIntervalPeriodTime(pointCalcBeginPeriodTime, tmseg, -1);
            }
        }
        if (maxEndTimeOffset != null && maxEndTimeOffset.intValue() != 0x0) {
            while (QmsTimeUtil.getIntervalPeriodTime(QmsTimeUtil.getNextPeriodTime(pointCalcEndPeriodTime, tmseg), maxEndTimeOffsetTmseg, maxEndTimeOffset.intValue()).isAfter(currentTime)) {
                //如果计算截止时段的时段末时间（下一个时段时间点）加上取数据截止偏移时段数＞当前时间，需要设置计算截止时段往前一个时段
                pointCalcEndPeriodTime = QmsTimeUtil.getIntervalPeriodTime(pointCalcEndPeriodTime, tmseg, -1);
            }
        }
        //如果计算出的开始时段＜最新定时计算时段时间，设置开始时段为最新定时计算时段的下一个时段
        if (pointLatestCalcPeriodTime != null && pointCalcBeginPeriodTime.isBefore(pointLatestCalcPeriodTime)) {
            pointCalcBeginPeriodTime = LocalDateTime.of(pointLatestCalcPeriodTime.toLocalDate(), pointLatestCalcPeriodTime.toLocalTime());
        }

        //设置返回结果中的计算起止时段
        result.setCalcBeginPeriodTime(pointCalcBeginPeriodTime);
        result.setCalcEndPeriodTime(pointCalcEndPeriodTime);

        //验证计算时段是否需要计算：开始时段≤截止时段，并且截止时段＞最新定时计算时段时间
        if (pointCalcEndPeriodTime.isBefore(pointCalcBeginPeriodTime)) {
            //计算出的截止时段＜开始时段，不进行计算
            String msg = "计算点号[" + pointid + "]，时段类型[" + tmseg + "]，本次定时计算时间段为["
                    + QmsTimeUtil.format(pointCalcBeginPeriodTime, tmseg) + "]-[" + QmsTimeUtil.format(pointCalcEndPeriodTime, tmseg)
                    + "]，当前时间所在时段[" + QmsTimeUtil.format(currentPeriodTime, tmseg) + "]，点号最新计算时段[" + QmsTimeUtil.format(pointLatestCalcPeriodTime, tmseg)
                    + "]，最大起始时间偏移时段[" + maxBeginTimeOffset + "][" + maxBeginTimeOffsetTmseg + "]，最大截止时间偏移时段[" + maxEndTimeOffset + "][" + maxEndTimeOffsetTmseg +
                    "]，计算出的截止时段时间＜开始时段，本次不进行定时计算";
            result.setMsg(msg);
            return result;
        } else {
            if (pointLatestCalcPeriodTime != null && pointLatestCalcPeriodTime.isBefore(pointCalcEndPeriodTime) == false) {
                //最新定时计算时段时间不为null，并且≥截止时段，不进行计算
                String msg = "计算点号[" + pointid + "]，时段类型[" + tmseg + "]，本次定时计算时间段为["
                        + QmsTimeUtil.format(pointCalcBeginPeriodTime, tmseg) + "]-[" + QmsTimeUtil.format(pointCalcEndPeriodTime, tmseg)
                        + "]，当前时间所在时段[" + QmsTimeUtil.format(currentPeriodTime, tmseg) + "]，点号最新计算时段[" + QmsTimeUtil.format(pointLatestCalcPeriodTime, tmseg)
                        + "]，最大起始时间偏移时段[" + maxBeginTimeOffset + "][" + maxBeginTimeOffsetTmseg + "]，最大截止时间偏移时段[" + maxEndTimeOffset + "][" + maxEndTimeOffsetTmseg +
                        "]，计算出的截止时段时间＜点号最新计算时段，本次不进行定时计算";
                result.setMsg(msg);
                return result;
            } else {
                //计算时段有效，进行计算
                String msg = "计算点号[" + pointid + "]，时段类型[" + tmseg + "]，本次定时计算时间段为["
                        + QmsTimeUtil.format(pointCalcBeginPeriodTime, tmseg) + "]-[" + QmsTimeUtil.format(pointCalcEndPeriodTime, tmseg)
                        + "]，当前时间所在时段[" + QmsTimeUtil.format(currentPeriodTime, tmseg) + "]，点号最新计算时段[" + QmsTimeUtil.format(pointLatestCalcPeriodTime, tmseg)
                        + "]，最大起始时间偏移时段[" + maxBeginTimeOffset + "][" + maxBeginTimeOffsetTmseg + "]，最大截止时间偏移时段[" + maxEndTimeOffset + "][" + maxEndTimeOffsetTmseg +
                        "]，定时计算时段有效，本次进行定时计算";
                result.setMsg(msg);
                //设置返回结果中的是否需要计算为true
                result.setNeedCalc(true);
                return result;

            }
        }
    }

    /**
     * 获取人工任务点号数据计算时本次要进行计算的点号时间段；人工任务计算点号的时间≤定时自动计算的时间
     *
     * @param point      点号对象
     * @param tmseg      点号时段类型
     * @param calcMethod 计算方法
     * @param beginTime  计算点号的起始时标，方法中会自动根据点号时段类型进行再次规整
     * @param endTime    计算点号的截止时标，方法中会自动根据点号时段类型进行再次规整
     * @return qc.module.qms.dto.calc.QmsPointDataCalcJudgeResultDto
     * @author QuCheng Tech
     * @since 2025/10/30
     */
    public QmsPointDataCalcJudgeResultDto getManualTaskCalcPointDataJudgeResult(QmsPoint point, QmsPointTimeSegmentEnum tmseg,
                                                                                QmsNumericCalcUseMethod calcMethod, LocalDateTime beginTime, LocalDateTime endTime) {
        //先初始化返回结果默认为不需要计算
        QmsPointDataCalcJudgeResultDto result = new QmsPointDataCalcJudgeResultDto();
        result.setNeedCalc(false);

        //判断基本输入是否正确，不正确时设置对应的提示信息并返回结果
        if (point == null) {
            result.setMsg("计算的点号对象不能为空");
            return result;
        }
        if (StringUtils.isBlank(point.getPointid())) {
            result.setMsg("计算的点号编码不能为空");
            return result;
        }
        if (tmseg == null) {
            result.setMsg("计算的时段类型不能为空");
            return result;
        }
        if (tmseg == QmsPointTimeSegmentEnum.UN_DEFINE || tmseg == QmsPointTimeSegmentEnum.REAL || tmseg == QmsPointTimeSegmentEnum.MINUTE) {
            result.setMsg("计算的时段类型错误");
            return result;
        }
        //判断计算方法
        if (calcMethod == null) {
            result.setMsg("计算方法不能为空");
            return result;
        }
        //传入的起始和截止时间必须正确
        if (beginTime == null) {
            result.setMsg("计算起始时间不能为空");
            return result;
        }
        if (endTime == null) {
            result.setMsg("计算截止时间不能为空");
            return result;
        }
        if (beginTime.isAfter(endTime) == true) {
            result.setMsg("计算起始时间不能大于截止时间");
            return result;
        }

        //先根据点号的时段类型对人工任务中的计算时间段进行规整
        LocalDateTime regularBeginTime = QmsTimeUtil.getPeriodTime(beginTime, tmseg);
        LocalDateTime regularEndTime = QmsTimeUtil.getPeriodTime(endTime, tmseg);

        String pointid = point.getPointid();
        //获取点号定时计算的数据时标
        LocalDateTime pointLatestCalcPeriodTime = pointDataLatestService.getCalcDataTime(pointid, tmseg);
        if (pointLatestCalcPeriodTime == null) {
            //没有定时计算的数据时标记录，固定使用当前时间所在时段进行判断；不再根据点号计算的输入数据取数配置进行复杂判断处理
            LocalDateTime nowPeriodTime = QmsTimeUtil.getPeriodTime(LocalDateTimeUtil.getNow(), tmseg);
            if (regularBeginTime.isAfter(nowPeriodTime) == true) {
                //如果人工任务中的计算点号起始时间＞定时计算的数据时间；判断为不需要进行计算
                result.setMsg("定时计算点号数据时段时间为空，计算点号数据人工任务中的起始时段时间[" + QmsTimeUtil.format(regularBeginTime, tmseg) +
                        "]＞当前时段时间[" + QmsTimeUtil.format(nowPeriodTime, tmseg) + "]");
            } else {
                //人工任务中的计算点号起始时间≤定时计算的数据时间，判定为需要计算
                result.setNeedCalc(true);
                result.setCalcBeginPeriodTime(regularBeginTime);
                result.setCalcEndPeriodTime(regularEndTime);

                if (regularEndTime.isAfter(nowPeriodTime) == true) {
                    //人工任务中的计算点号截止时间＞定时计算的数据时间，设置计算的截止时间为定时计算的数据时间；往后的时间由定时计算完成
                    result.setMsg("定时计算点号数据时段时间为空，计算点号数据人工任务中的截止时段时间[" + QmsTimeUtil.format(regularEndTime, tmseg) +
                            "]＞当前时段时间[" + QmsTimeUtil.format(nowPeriodTime, tmseg) + "]，已自动设置当前时段时间为本次计算的截止时段时间。");
                    result.setCalcEndPeriodTime(nowPeriodTime);
                }
            }
        } else {
            if (regularBeginTime.isAfter(pointLatestCalcPeriodTime) == true) {
                //如果人工任务中的计算点号起始时间＞定时计算的数据时间；判断为不需要进行计算
                result.setMsg("计算点号数据人工任务中的起始时段时间[" + QmsTimeUtil.format(regularBeginTime, tmseg) +
                        "]＞定时计算点号数据时段时间[" + QmsTimeUtil.format(pointLatestCalcPeriodTime, tmseg) + "]");
            } else {
                //人工任务中的计算点号起始时间≤定时计算的数据时间，判定为需要计算
                result.setNeedCalc(true);
                result.setCalcBeginPeriodTime(regularBeginTime);
                result.setCalcEndPeriodTime(regularEndTime);

                if (regularEndTime.isAfter(pointLatestCalcPeriodTime) == true) {
                    //人工任务中的计算点号截止时间＞定时计算的数据时间，设置计算的截止时间为定时计算的数据时间；往后的时间由定时计算完成
                    result.setMsg("计算点号数据人工任务中的截止时段时间[" + QmsTimeUtil.format(regularEndTime, tmseg) +
                            "]＞定时计算点号数据时段时间[" + QmsTimeUtil.format(pointLatestCalcPeriodTime, tmseg) + "]，已自动设置定时计算点号数据时段时间为本次计算的截止时段时间。");
                    result.setCalcEndPeriodTime(pointLatestCalcPeriodTime);
                }
            }
        }

        return result;
    }
}
